package glemipsc.instructions;

import glemipsc.Address;
import glemipsc.Function;
import glemipsc.GLEMipsC;
import glemipsc.Type;
import glemipsc.implementations.Argument;
import glemipsc.implementations.Implementation;

import java.io.Serializable;
import java.util.List;

public class Div extends BaseInstruction implements Serializable, Instruction, Expression {
	private Expression op1, op2;
	private Type type;
	private Address addr;
	
	public Div(Expression op1, Expression op2) {
		this.op1 = op1;
		this.op2 = op2;
		type = Type.getCommonType(op1.getType(), op2.getType());
	}
	
	public Expression getOperand(int index) {
		if (index == 0)
			return op1;
		else if (index == 1)
			return op2;
		return null;
	}
	
	public int getNumberOfOperands() {
		return 2;
	}

	public int getSize() {
		return 0;
	}

	public Type getType() {
		return type;
	}

	public int getImmediateValue() {
		return op1.getImmediateValue() / op2.getImmediateValue();
	}

	public boolean isImmediate() {
		return op1.isImmediate() && op2.isImmediate();
	}

	public Address getStoreAddress() {
		return addr;
	}

	public int getStoredSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	public boolean isStored() {
		return !isImmediate();
	}

	public void setStoreAddress(Address addr) {
		this.addr = addr;
	}

	public void computeInstruction(Argument result, List<glemipsc.implementations.Instruction> instructions, Function func) {
		Implementation impl = GLEMipsC.compiler.getEnvironment().implementation;
		Argument s1 = null, s2 = null;
		
		if (!op1.isImmediate()) {
			s1 = impl.getFreeRegister();
			op1.computeInstruction(s1, instructions, func);
		}
		if (!op2.isImmediate()) {
			s2 = impl.getFreeRegister();
			op2.computeInstruction(s2, instructions, func);
		}
		if (op1.isImmediate()) {
			instructions.add(impl.getDiv(result, s2, impl.getImmediate(op1.getImmediateValue()), type.isSigned()));
			impl.freeRegister(s2);
		}
		else if (op2.isImmediate()) {
			instructions.add(impl.getDiv(result, s1, impl.getImmediate(op2.getImmediateValue()), type.isSigned()));
			impl.freeRegister(s1);
		}
		else {
			instructions.add(impl.getDiv(result, s1, s2, type.isSigned()));
			impl.freeRegister(s1);
			impl.freeRegister(s2);
		}
	}

}
